package com.gc.cscott.cli;

import com.gc.cscott.domain.contest.Contest;
import com.gc.cscott.domain.contest.Task;
import com.gc.cscott.domain.contest.TestCase;
import com.gc.cscott.domain.result.CompetitorResult;
import com.gc.cscott.domain.result.TestCaseResult;
import com.gc.cscott.fs.FileSystemWorker;
import com.gc.cscott.store.ResultsStorage;
import com.gc.cscott.domain.Competitor;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author dmitry.mamonov
 */
public class ReportPersonalResultsCommand implements Command {
    @Inject
    Contest contest;

    @Inject
    FileSystemWorker fsWorker;

    @Inject
    ResultsStorage resultsStorage;

    boolean modeEditResults = false;

    public List<String> listHelp() {
        return Arrays.asList(
                "Report results of a single competitor.",
                "Options:",
                "  <name> - any word to find competitor by name (required)",
                "  edit - results will be opened in editor instead of printing to stdout (optional)"
                );
    }

    public List<String> perform(List<String> args) {
        if (args.isEmpty()) {
            throw new Error("No competitors name specified");
        } else {
            try {
                LinkedList<String> mutableArgs = new LinkedList<String>(args);
                final String likeName = mutableArgs.removeFirst();
                if (mutableArgs.isEmpty()==false){
                    if ("edit".equals(mutableArgs.getFirst())){
                        modeEditResults=true;
                        mutableArgs.removeFirst();
                    }
                }
                final File outputFile;
                final PrintStream output;
                if (modeEditResults){
                    outputFile = File.createTempFile("personal-results-", ".txt");
                    output = new PrintStream(outputFile);
                } else {
                    outputFile=null;
                    output = System.out;
                }

                List<Competitor> competitorsList = (fsWorker.listCompetitorsAll());
                if (competitorsList.isEmpty()) {
                    output.println("No competitors found.");
                } else {
                    Competitor nearest = Collections.min(competitorsList, new Comparator<Competitor>() {
                        public int compare(Competitor left, Competitor right) {
                            int leftDistance = StringUtils.getLevenshteinDistance(left.getName(), likeName);
                            int rightDistance = StringUtils.getLevenshteinDistance(right.getName(), likeName);
                            return leftDistance - rightDistance;
                        }
                    });
                    final int nearestDistance = StringUtils.getLevenshteinDistance(nearest.getName(), likeName);
                    int countOfNearestCompetitors = 0;
                    for (Competitor competitor : competitorsList) {
                        final int competitorDistance = StringUtils.getLevenshteinDistance(competitor.getName(), likeName);
                        if (nearestDistance == competitorDistance) {
                            output.println("Competitor name: '" + competitor.getName() + "' at " + competitor.getBasedir());
                            countOfNearestCompetitors++;
                        }
                    }
                    if (countOfNearestCompetitors == 1) {
                        CompetitorResult result = resultsStorage.loadResults(nearest);
                        int totalPassed = 0;
                        int totalFailed = 0;
                        int totalScore  = 0;
                        for (Task task : contest.getTasksList()) {
                            output.printf("Task %2d '%s'", task.getNumber().intValue(), task.getName());
                            output.println();
                            output.println(StringUtils.repeat("-", 60));
                            int testPassed = 0;
                            int testFailed = 0;
                            int testScore  = 0;
                            for (TestCase testCase : task.getTestCaseList()) {
                                TestCaseResult tcr = result.getResult(testCase);
                                if (tcr!=null){
                                    if (tcr.getResult()== TestCaseResult.HowEnded.Correct){
                                        testPassed++;
                                        testScore+=testCase.getScore();
                                    } else {
                                        testFailed++;
                                    }
                                    output.printf("  test %2d [%5dms] %-18s %s",
                                            tcr.getTestCaseNumber().intValue(),
                                            tcr.getPayedTime(),
                                            tcr.getResult()+
                                            (tcr.getResult()== TestCaseResult.HowEnded.Correct
                                            ?String.format(", score +%2d",testCase.getScore())
                                            :""),
                                            (StringUtils.isBlank(tcr.getHint())?"":"- ")+
                                            StringUtils.defaultString(tcr.getHint()).replace("\n", " ").replace("\r", " "));
                                    output.println();
                                } else {
                                    output.printf("  test %2d - no solution", testCase.getNumber().intValue());
                                    output.println();
                                }
                            }
                            totalPassed+=testPassed;
                            totalFailed+=testFailed;
                            totalScore+=testScore;
                            output.printf("%20s passed %3d, failed %3d, score %3d", "",testPassed, testFailed, testScore);
                            output.println();
                        }
                        output.printf("%20s PASSED %3d, FAILED %3d, SCORE %3d", "",totalPassed, totalFailed, totalScore);
                        output.println();
                    } else {
                        output.println();
                        output.println("Please specify a name more precisely.");
                    }
                }

                if (outputFile!=null){
                    output.close();
                    Desktop.getDesktop().edit(outputFile);
                }


                return ImmutableList.copyOf(mutableArgs);
            } catch (IOException e) {
                throw new Error(e);
            }
        }
    }
}
